///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2004, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "../api.h"
#include "iofuncs.h"
#include "common.h"
#include "cirbuf.h"

extern histories_t *histories;
query_buf_t	query_buf;

int
io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb)
{
	int					sts;
	void				*data;
	int					nbytes;
	int					dcmd;
	int					len;
	char				*name;
	int					i;
	cfg_t				*cfg;

/*
 *	WARNING:  check in main.c to see if you need to adjust the "nparts_max" and "msg_max_size"
*/


	// see if it's a standard POSIX-supported devctl()
	if ((sts = iofunc_devctl_default (ctp, msg, ocb)) != _RESMGR_DEFAULT) {
		return (sts);
	}

	// assign a pointer to the data area of the message
	data = _DEVCTL_DATA (*msg);

	// get other data that can't be wiped out before we wipe the data structure
	dcmd = msg -> i.dcmd;
	len = msg -> i.nbytes;
	memset (&msg -> o, 0, sizeof (msg -> o));

	// preset the number of bytes that we'll return to zero
	nbytes = 0;

	// check for all commands
	switch (dcmd) {

	case DCMD_GET_FTREND:

		name = (char *) data;
		for (i= 0; i< histories->ncfg; i++) {
			cfg = &histories->cfg [i];
			if (!strcmp (cfg->point_name, name)) {
				if (query_buf.values) {
					free (query_buf.values);
					query_buf.values = NULL;
					query_buf.nvalues = 0;
				}
				if (query_buf.name) {
					free (query_buf.name);
					query_buf.name = NULL;
				}
				query_buf.name = strdup (name);
				query_buf.nvalues = cirbuf_to_buf (cfg->buf, &query_buf.values);
				if (query_buf.nvalues < 0) {
					fprintf (stderr, "Can't cirbuf_to_buf in devctl\n");
					exit (EXIT_FAILURE);
				}
				ocb->attr->nbytes = query_buf.nvalues * sizeof (pt_t);
			}			
		}
		break;
		
	case DCMD_FREE_FTREND:
		break;

	default:
		return (ENOSYS);
	}

	// return data (if any) to the client
	msg -> o.nbytes = nbytes;
	SETIOV (ctp -> iov, &msg -> o, sizeof (msg -> o) + nbytes);
	return (_RESMGR_NPARTS (1));
}


int
io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb)
{
    int         nleft;
    int         nbytes;
    int         nparts;
    int         status;

    if ((status = iofunc_read_verify (ctp, msg, ocb, NULL)) != EOK)
        return (status);
        
    if (msg->i.xtype & _IO_XTYPE_MASK != _IO_XTYPE_NONE)
        return (ENOSYS);

    /*
     *  On all reads (first and subsequent), calculate
     *  how many bytes we can return to the client,
     *  based upon the number of bytes available (nleft)
     *  and the client's buffer size
     */
     
    nleft = ocb->attr->nbytes - ocb->offset;
    nbytes = min (msg->i.nbytes, nleft);

    if (nbytes > 0) {
        /* set up the return data IOV */
        SETIOV (ctp->iov, (void *)(query_buf.values) + ocb->offset, nbytes);

        /* set up the number of bytes (returned by client's read()) */
        _IO_SET_READ_NBYTES (ctp, nbytes);

        /*
         * advance the offset by the number of bytes
         * returned to the client.
         */

        ocb->offset += nbytes;
        
        nparts = 1;
    } else {
        /*
         * they've asked for zero bytes or they've already previously
         * read everything
         */
        
        _IO_SET_READ_NBYTES (ctp, 0);
        
        nparts = 0;
    }

    /* mark the access time as invalid (we just accessed it) */

    if (msg->i.nbytes > 0)
        ocb->attr->flags |= IOFUNC_ATTR_ATIME;

    return (_RESMGR_NPARTS (nparts));
}